﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LispInterpretor.HelperClasses;

namespace LispInterpretor.Parsers
{
    public class LetParser : IParser
    {
        #region IParser Members

        bool IParser.Is(string text, Environment environment)
        {
            return text.StartsWith("(let", StringComparison.InvariantCultureIgnoreCase) && text.EndsWith(")", StringComparison.InvariantCultureIgnoreCase);
        }

        object IParser.Evaluate(string text, Environment environment)
        {
            IList<string> argList = ParserHelper.ParseArguments(text);

            Check.IsTrue(argList.Count == 3, "A let expression requires two parameters: a list of bindings and an expression.");

            string bindingList = argList[1];
            string expression = argList[2];

            Environment bindingEnvironment = new Environment(environment);

            Bind(bindingEnvironment, bindingList);

            return Evaluator.Eval(expression, bindingEnvironment);
        }

        private void Bind(Environment bindingEnvironment, string bindingList)
        {
            IList<string> unpackedList = ParserHelper.ParseArguments(bindingList);

            foreach (string binding in unpackedList)
            {
                IList<string> pair = ParserHelper.ParseArguments(binding);

                Check.IsTrue(pair.Count == 2, "Each binding should consist of a pair. A label and an expression.");

                // We evaluate the pair's expression against the parent environment so that
                // each expression can't be aware of the others in the binding list.
                // This means, in theory, we could modify the interpreter later to execute these bindings in parallel.
                bindingEnvironment.Add(pair[0], Evaluator.Eval(pair[1], bindingEnvironment.Parent));

            }
        }

        #endregion
    }
}
